home *** CD-ROM | disk | FTP | other *** search
- #include <assert.h>
- #include "qe3.h"
-
- #define MAX_POINTS_ON_WINDING 64
-
- face_t *Face_Alloc( void );
- void Face_Free( face_t *f );
-
- winding_t *NewWinding (int points);
- void FreeWinding (winding_t *w);
- winding_t *Winding_Clone( winding_t *w );
- winding_t *ClipWinding (winding_t *in, plane_t *split, qboolean keepon);
-
- void PrintWinding (winding_t *w)
- {
- int i;
-
- printf ("-------------\n");
- for (i=0 ; i<w->numpoints ; i++)
- printf ("(%5.2f, %5.2f, %5.2f)\n", w->points[i][0]
- , w->points[i][1], w->points[i][2]);
- }
-
- void PrintPlane (plane_t *p)
- {
- printf ("(%5.2f, %5.2f, %5.2f) : %5.2f\n", p->normal[0], p->normal[1],
- p->normal[2], p->dist);
- }
-
- void PrintVector (vec3_t v)
- {
- printf ("(%5.2f, %5.2f, %5.2f)\n", v[0], v[1], v[2]);
- }
-
-
- face_t *Face_Clone (face_t *f)
- {
- face_t *n;
-
- n = Face_Alloc();
- n->texdef = f->texdef;
- memcpy (n->planepts, f->planepts, sizeof(n->planepts));
-
- // all other fields are derived, and will be set by Brush_Build
- return n;
- }
-
- //============================================================================
-
- #define BOGUS_RANGE 18000
-
-
- /*
- ==================
- NewWinding
- ==================
- */
- winding_t *NewWinding (int points)
- {
- winding_t *w;
- int size;
-
- if (points > MAX_POINTS_ON_WINDING)
- Error ("NewWinding: %i points", points);
-
- size = (int)((winding_t *)0)->points[points];
- w = malloc (size);
- memset (w, 0, size);
- w->maxpoints = points;
-
- return w;
- }
-
-
- void FreeWinding (winding_t *w)
- {
- free (w);
- }
-
-
- /*
- ==================
- Winding_Clone
- ==================
- */
- winding_t *Winding_Clone(winding_t *w)
- {
- int size;
- winding_t *c;
-
- size = (int)((winding_t *)0)->points[w->numpoints];
- c = qmalloc (size);
- memcpy (c, w, size);
- return c;
- }
-
-
- /*
- ==================
- ClipWinding
-
- Clips the winding to the plane, returning the new winding on the positive side
- Frees the input winding.
- If keepon is true, an exactly on-plane winding will be saved, otherwise
- it will be clipped away.
- ==================
- */
- winding_t *ClipWinding (winding_t *in, plane_t *split, qboolean keepon)
- {
- vec_t dists[MAX_POINTS_ON_WINDING];
- int sides[MAX_POINTS_ON_WINDING];
- int counts[3];
- vec_t dot;
- int i, j;
- vec_t *p1, *p2;
- vec3_t mid;
- winding_t *neww;
- int maxpts;
-
- counts[0] = counts[1] = counts[2] = 0;
-
- // determine sides for each point
- for (i=0 ; i<in->numpoints ; i++)
- {
- dot = DotProduct (in->points[i], split->normal);
- dot -= split->dist;
- dists[i] = dot;
- if (dot > ON_EPSILON)
- sides[i] = SIDE_FRONT;
- else if (dot < -ON_EPSILON)
- sides[i] = SIDE_BACK;
- else
- {
- sides[i] = SIDE_ON;
- }
- counts[sides[i]]++;
- }
- sides[i] = sides[0];
- dists[i] = dists[0];
-
- if (keepon && !counts[0] && !counts[1])
- return in;
-
- if (!counts[0])
- {
- FreeWinding (in);
- return NULL;
- }
- if (!counts[1])
- return in;
-
- maxpts = in->numpoints+4; // can't use counts[0]+2 because
- // of fp grouping errors
- neww = NewWinding (maxpts);
-
- for (i=0 ; i<in->numpoints ; i++)
- {
- p1 = in->points[i];
-
- if (sides[i] == SIDE_ON)
- {
- VectorCopy (p1, neww->points[neww->numpoints]);
- neww->numpoints++;
- continue;
- }
-
- if (sides[i] == SIDE_FRONT)
- {
- VectorCopy (p1, neww->points[neww->numpoints]);
- neww->numpoints++;
- }
-
- if (sides[i+1] == SIDE_ON || sides[i+1] == sides[i])
- continue;
-
- // generate a split point
- p2 = in->points[(i+1)%in->numpoints];
-
- dot = dists[i] / (dists[i]-dists[i+1]);
- for (j=0 ; j<3 ; j++)
- { // avoid round off error when possible
- if (split->normal[j] == 1)
- mid[j] = split->dist;
- else if (split->normal[j] == -1)
- mid[j] = -split->dist;
- else
- mid[j] = p1[j] + dot*(p2[j]-p1[j]);
- }
-
- VectorCopy (mid, neww->points[neww->numpoints]);
- neww->numpoints++;
- }
-
- if (neww->numpoints > maxpts)
- Error ("ClipWinding: points exceeded estimate");
-
- // free the original winding
- FreeWinding (in);
-
- return neww;
- }
-
-
-
- /*
- =============================================================================
-
- TEXTURE COORDINATES
-
- =============================================================================
- */
-
-
- /*
- ==================
- textureAxisFromPlane
- ==================
- */
- vec3_t baseaxis[18] =
- {
- {0,0,1}, {1,0,0}, {0,-1,0}, // floor
- {0,0,-1}, {1,0,0}, {0,-1,0}, // ceiling
- {1,0,0}, {0,1,0}, {0,0,-1}, // west wall
- {-1,0,0}, {0,1,0}, {0,0,-1}, // east wall
- {0,1,0}, {1,0,0}, {0,0,-1}, // south wall
- {0,-1,0}, {1,0,0}, {0,0,-1} // north wall
- };
-
- void TextureAxisFromPlane(plane_t *pln, vec3_t xv, vec3_t yv)
- {
- int bestaxis;
- float dot,best;
- int i;
-
- best = 0;
- bestaxis = 0;
-
- for (i=0 ; i<6 ; i++)
- {
- dot = DotProduct (pln->normal, baseaxis[i*3]);
- if (dot > best)
- {
- best = dot;
- bestaxis = i;
- }
- }
-
- VectorCopy (baseaxis[bestaxis*3+1], xv);
- VectorCopy (baseaxis[bestaxis*3+2], yv);
- }
-
-
- float lightaxis[3] = {0.6, 0.8, 1.0};
- /*
- ================
- SetShadeForPlane
-
- Light different planes differently to
- improve recognition
- ================
- */
- float SetShadeForPlane (plane_t *p)
- {
- int i;
- float f;
-
- // axial plane
- for (i=0 ; i<3 ; i++)
- if (fabs(p->normal[i]) > 0.9)
- {
- f = lightaxis[i];
- return f;
- }
-
- // between two axial planes
- for (i=0 ; i<3 ; i++)
- if (fabs(p->normal[i]) < 0.1)
- {
- f = (lightaxis[(i+1)%3] + lightaxis[(i+2)%3])/2;
- return f;
- }
-
- // other
- f= (lightaxis[0] + lightaxis[1] + lightaxis[2]) / 3;
- return f;
- }
-
- vec3_t vecs[2];
- float shift[2];
-
- /*
- ================
- BeginTexturingFace
- ================
- */
- void BeginTexturingFace (brush_t *b, face_t *f, qtexture_t *q)
- {
- vec3_t pvecs[2];
- int sv, tv;
- float ang, sinv, cosv;
- float ns, nt;
- int i,j;
- float shade;
-
- // get natural texture axis
- TextureAxisFromPlane(&f->plane, pvecs[0], pvecs[1]);
-
- // set shading for face
- shade = SetShadeForPlane (&f->plane);
- if (camera.draw_mode == cd_texture && !b->owner->eclass->fixedsize)
- {
- f->d_color[0] =
- f->d_color[1] =
- f->d_color[2] = shade;
- }
- else
- {
- f->d_color[0] = shade*q->color[0];
- f->d_color[1] = shade*q->color[1];
- f->d_color[2] = shade*q->color[2];
- }
-
- if (camera.draw_mode != cd_texture)
- return;
-
- if (!f->texdef.scale[0])
- f->texdef.scale[0] = 1;
- if (!f->texdef.scale[1])
- f->texdef.scale[1] = 1;
-
-
- // rotate axis
- if (f->texdef.rotate == 0)
- { sinv = 0 ; cosv = 1; }
- else if (f->texdef.rotate == 90)
- { sinv = 1 ; cosv = 0; }
- else if (f->texdef.rotate == 180)
- { sinv = 0 ; cosv = -1; }
- else if (f->texdef.rotate == 270)
- { sinv = -1 ; cosv = 0; }
- else
- {
- ang = f->texdef.rotate / 180 * Q_PI;
- sinv = sin(ang);
- cosv = cos(ang);
- }
-
- if (pvecs[0][0])
- sv = 0;
- else if (pvecs[0][1])
- sv = 1;
- else
- sv = 2;
-
- if (pvecs[1][0])
- tv = 0;
- else if (pvecs[1][1])
- tv = 1;
- else
- tv = 2;
-
- for (i=0 ; i<2 ; i++)
- {
- ns = cosv * pvecs[i][sv] - sinv * pvecs[i][tv];
- nt = sinv * pvecs[i][sv] + cosv * pvecs[i][tv];
- vecs[i][sv] = ns;
- vecs[i][tv] = nt;
- }
-
- for (i=0 ; i<2 ; i++)
- for (j=0 ; j<3 ; j++)
- vecs[i][j] = vecs[i][j] / f->texdef.scale[i];
- }
-
-
- void _EmitTextureCoordinates (vec3_t v, qtexture_t *q)
- {
- float s, t;
-
- s = DotProduct (v, vecs[0]);
- t = DotProduct (v, vecs[1]);
-
- s += shift[0];
- t += shift[1];
-
- s /= q->width;
- t /= q->height;
-
- glTexCoord2f (s, t);
- }
-
- void EmitTextureCoordinates ( float *xyzst, qtexture_t *q, face_t *f)
- {
- float s, t, ns, nt;
- float ang, sinv, cosv;
- vec3_t vecs[2];
- texdef_t *td;
-
- // get natural texture axis
- TextureAxisFromPlane(&f->plane, vecs[0], vecs[1]);
-
- td = &f->texdef;
-
- ang = td->rotate / 180 * Q_PI;
- sinv = sin(ang);
- cosv = cos(ang);
-
- if (!td->scale[0])
- td->scale[0] = 1;
- if (!td->scale[1])
- td->scale[1] = 1;
-
- s = DotProduct(xyzst, vecs[0]);
- t = DotProduct(xyzst, vecs[1]);
-
- ns = cosv * s - sinv * t;
- nt = sinv * s + cosv * t;
-
- s = ns/td->scale[0] + td->shift[0];
- t = nt/td->scale[1] + td->shift[1];
-
- // gl scales everything from 0 to 1
- s /= q->width;
- t /= q->height;
-
- xyzst[3] = s;
- xyzst[4] = t;
- }
-
- //==========================================================================
-
-
- /*
- =================
- BasePolyForPlane
- =================
- */
- winding_t *BasePolyForPlane (plane_t *p)
- {
- int i, x;
- vec_t max, v;
- vec3_t org, vright, vup;
- winding_t *w;
-
- // find the major axis
-
- max = -BOGUS_RANGE;
- x = -1;
- for (i=0 ; i<3; i++)
- {
- v = fabs(p->normal[i]);
- if (v > max)
- {
- x = i;
- max = v;
- }
- }
- if (x==-1)
- Error ("BasePolyForPlane: no axis found");
-
- VectorCopy (vec3_origin, vup);
- switch (x)
- {
- case 0:
- case 1:
- vup[2] = 1;
- break;
- case 2:
- vup[0] = 1;
- break;
- }
-
-
- v = DotProduct (vup, p->normal);
- VectorMA (vup, -v, p->normal, vup);
- VectorNormalize (vup);
-
- VectorScale (p->normal, p->dist, org);
-
- CrossProduct (vup, p->normal, vright);
-
- VectorScale (vup, 8192, vup);
- VectorScale (vright, 8192, vright);
-
- // project a really big axis aligned box onto the plane
- w = NewWinding (4);
-
- VectorSubtract (org, vright, w->points[0]);
- VectorAdd (w->points[0], vup, w->points[0]);
-
- VectorAdd (org, vright, w->points[1]);
- VectorAdd (w->points[1], vup, w->points[1]);
-
- VectorAdd (org, vright, w->points[2]);
- VectorSubtract (w->points[2], vup, w->points[2]);
-
- VectorSubtract (org, vright, w->points[3]);
- VectorSubtract (w->points[3], vup, w->points[3]);
-
- w->numpoints = 4;
-
- return w;
- }
-
- void Brush_MakeFacePlanes (brush_t *b)
- {
- face_t *f;
- int j;
- vec3_t t1, t2, t3;
-
- for (f=b->brush_faces ; f ; f=f->next)
- {
- // convert to a vector / dist plane
- for (j=0 ; j<3 ; j++)
- {
- t1[j] = f->planepts[0][j] - f->planepts[1][j];
- t2[j] = f->planepts[2][j] - f->planepts[1][j];
- t3[j] = f->planepts[1][j];
- }
-
- CrossProduct(t1,t2, f->plane.normal);
- if (VectorCompare (f->plane.normal, vec3_origin))
- printf ("WARNING: brush plane with no normal\n");
- VectorNormalize (f->plane.normal);
- f->plane.dist = DotProduct (t3, f->plane.normal);
- }
- }
-
- void DrawBrushEntityName (brush_t *b)
- {
- char *name;
- float a, s, c;
- vec3_t mid;
- int i;
-
- if (!b->owner)
- return; // during contruction
-
- if (b->owner == world_entity)
- return;
-
- if (b != b->owner->brushes.onext)
- return; // not key brush
-
- // draw the angle pointer
- a = FloatForKey (b->owner, "angle");
- if (a)
- {
- s = sin (a/180*Q_PI);
- c = cos (a/180*Q_PI);
- for (i=0 ; i<3 ; i++)
- mid[i] = (b->mins[i] + b->maxs[i])*0.5;
-
- glBegin (GL_LINE_STRIP);
- glVertex3fv (mid);
- mid[0] += c*8;
- mid[1] += s*8;
- glVertex3fv (mid);
- mid[0] -= c*4;
- mid[1] -= s*4;
- mid[0] -= s*4;
- mid[1] += c*4;
- glVertex3fv (mid);
- mid[0] += c*4;
- mid[1] += s*4;
- mid[0] += s*4;
- mid[1] -= c*4;
- glVertex3fv (mid);
- mid[0] -= c*4;
- mid[1] -= s*4;
- mid[0] += s*4;
- mid[1] -= c*4;
- glVertex3fv (mid);
- glEnd ();
- }
-
- if (!g_qeglobals.d_savedinfo.show_names)
- return;
-
- name = ValueForKey (b->owner, "classname");
- glRasterPos2f (b->mins[0]+4, b->mins[1]+4);
- glCallLists (strlen(name), GL_UNSIGNED_BYTE, name);
- }
-
- /*
- =================
- MakeFaceWinding
-
- returns the visible polygon on a face
- =================
- */
- winding_t *MakeFaceWinding (brush_t *b, face_t *face)
- {
- winding_t *w;
- face_t *clip;
- plane_t plane;
- qboolean past;
-
- // get a poly that covers an effectively infinite area
- w = BasePolyForPlane (&face->plane);
-
- // chop the poly by all of the other faces
- past = false;
- for (clip = b->brush_faces ; clip && w ; clip=clip->next)
- {
- if (clip == face)
- {
- past = true;
- continue;
- }
- if (DotProduct (face->plane.normal, clip->plane.normal) > 0.999
- && fabs(face->plane.dist - clip->plane.dist) < 0.01 )
- { // identical plane, use the later one
- if (past)
- {
- free (w);
- return NULL;
- }
- continue;
- }
-
- // flip the plane, because we want to keep the back side
- VectorSubtract (vec3_origin,clip->plane.normal, plane.normal);
- plane.dist = -clip->plane.dist;
-
- w = ClipWinding (w, &plane, false);
- if (!w)
- return w;
- }
-
- if (w->numpoints < 3)
- {
- free(w);
- w = NULL;
- }
-
- if (!w)
- printf ("unused plane\n");
-
- return w;
- }
-
-
- void Brush_SnapPlanepts (brush_t *b)
- {
- int i, j;
- face_t *f;
-
- for (f=b->brush_faces ; f; f=f->next)
- for (i=0 ; i<3 ; i++)
- for (j=0 ; j<3 ; j++)
- f->planepts[i][j] = floor (f->planepts[i][j] + 0.5);
- }
-
- /*
- ** Brush_Build
- **
- ** Builds a brush rendering data and also sets the min/max bounds
- */
- #define ZERO_EPSILON 0.001
- void Brush_Build( brush_t *b )
- {
- // int order;
- // face_t *face;
- // winding_t *w;
- char title[1024];
-
- if (modified != 1)
- {
- modified = true; // mark the map as changed
- sprintf (title, "%s *", currentmap);
-
- QE_ConvertDOSToUnixName( title, title );
- Sys_SetTitle (title);
- }
-
- /*
- ** build the windings and generate the bounding box
- */
- Brush_BuildWindings( b );
-
- /*
- ** move the points and edges if in select mode
- */
- if (g_qeglobals.d_select_mode == sel_vertex || g_qeglobals.d_select_mode == sel_edge)
- SetupVertexSelection ();
- }
-
- /*
- =================
- Brush_Parse
-
- The brush is NOT linked to any list
- =================
- */
- brush_t *Brush_Parse (void)
- {
- brush_t *b;
- face_t *f;
- int i,j;
-
- g_qeglobals.d_parsed_brushes++;
- b = qmalloc(sizeof(brush_t));
-
- do
- {
- if (!GetToken (true))
- break;
- if (!strcmp (token, "}") )
- break;
-
- f = Face_Alloc();
-
- // add the brush to the end of the chain, so
- // loading and saving a map doesn't reverse the order
-
- f->next = NULL;
- if (!b->brush_faces)
- {
- b->brush_faces = f;
- }
- else
- {
- face_t *scan;
-
- for (scan=b->brush_faces ; scan->next ; scan=scan->next)
- ;
- scan->next = f;
- }
-
- // read the three point plane definition
- for (i=0 ; i<3 ; i++)
- {
- if (i != 0)
- GetToken (true);
- if (strcmp (token, "(") )
- Error ("parsing brush");
-
- for (j=0 ; j<3 ; j++)
- {
- GetToken (false);
- f->planepts[i][j] = atoi(token);
- }
-
- GetToken (false);
- if (strcmp (token, ")") )
- Error ("parsing brush");
-
- }
-
- // read the texturedef
- GetToken (false);
- strcpy(f->texdef.name, token);
- GetToken (false);
- f->texdef.shift[0] = atoi(token);
- GetToken (false);
- f->texdef.shift[1] = atoi(token);
- GetToken (false);
- f->texdef.rotate = atoi(token);
- GetToken (false);
- f->texdef.scale[0] = atof(token);
- GetToken (false);
- f->texdef.scale[1] = atof(token);
-
- // the flags and value field aren't necessarily present
- f->d_texture = Texture_ForName( f->texdef.name );
- f->texdef.flags = f->d_texture->flags;
- f->texdef.value = f->d_texture->value;
- f->texdef.contents = f->d_texture->contents;
-
- if (TokenAvailable ())
- {
- GetToken (false);
- f->texdef.contents = atoi(token);
- GetToken (false);
- f->texdef.flags = atoi(token);
- GetToken (false);
- f->texdef.value = atoi(token);
- }
- } while (1);
-
- return b;
- }
-
- /*
- =================
- Brush_Write
- =================
- */
- void Brush_Write (brush_t *b, FILE *f)
- {
- face_t *fa;
- char *pname;
- int i;
-
- fprintf (f, "{\n");
- for (fa=b->brush_faces ; fa ; fa=fa->next)
- {
- for (i=0 ; i<3 ; i++)
- fprintf (f, "( %i %i %i ) ", (int)fa->planepts[i][0]
- , (int)fa->planepts[i][1], (int)fa->planepts[i][2]);
-
- pname = fa->texdef.name;
- if (pname[0] == 0)
- pname = "unnamed";
-
- fprintf (f, "%s %i %i %i ", pname,
- (int)fa->texdef.shift[0], (int)fa->texdef.shift[1],
- (int)fa->texdef.rotate);
-
- if (fa->texdef.scale[0] == (int)fa->texdef.scale[0])
- fprintf (f, "%i ", (int)fa->texdef.scale[0]);
- else
- fprintf (f, "%f ", (float)fa->texdef.scale[0]);
- if (fa->texdef.scale[1] == (int)fa->texdef.scale[1])
- fprintf (f, "%i", (int)fa->texdef.scale[1]);
- else
- fprintf (f, "%f", (float)fa->texdef.scale[1]);
-
- // only output flags and value if not default
- if (fa->texdef.value != fa->d_texture->value
- || fa->texdef.flags != fa->d_texture->flags
- || fa->texdef.contents != fa->d_texture->contents)
- {
- fprintf (f, " %i %i %i", fa->texdef.contents, fa->texdef.flags, fa->texdef.value);
- }
-
- fprintf (f, "\n");
- }
- fprintf (f, "}\n");
- }
-
-
- /*
- =============
- Brush_Create
-
- Create non-textured blocks for entities
- The brush is NOT linked to any list
- =============
- */
- brush_t *Brush_Create (vec3_t mins, vec3_t maxs, texdef_t *texdef)
- {
- int i, j;
- vec3_t pts[4][2];
- face_t *f;
- brush_t *b;
-
- for (i=0 ; i<3 ; i++)
- if (maxs[i] < mins[i])
- Error ("Brush_InitSolid: backwards");
-
- b = qmalloc (sizeof(brush_t));
-
- pts[0][0][0] = mins[0];
- pts[0][0][1] = mins[1];
-
- pts[1][0][0] = mins[0];
- pts[1][0][1] = maxs[1];
-
- pts[2][0][0] = maxs[0];
- pts[2][0][1] = maxs[1];
-
- pts[3][0][0] = maxs[0];
- pts[3][0][1] = mins[1];
-
- for (i=0 ; i<4 ; i++)
- {
- pts[i][0][2] = mins[2];
- pts[i][1][0] = pts[i][0][0];
- pts[i][1][1] = pts[i][0][1];
- pts[i][1][2] = maxs[2];
- }
-
- for (i=0 ; i<4 ; i++)
- {
- f = Face_Alloc();
- f->texdef = *texdef;
- f->next = b->brush_faces;
- b->brush_faces = f;
- j = (i+1)%4;
-
- VectorCopy (pts[j][1], f->planepts[0]);
- VectorCopy (pts[i][1], f->planepts[1]);
- VectorCopy (pts[i][0], f->planepts[2]);
- }
-
- f = Face_Alloc();
- f->texdef = *texdef;
- f->next = b->brush_faces;
- b->brush_faces = f;
-
- VectorCopy (pts[0][1], f->planepts[0]);
- VectorCopy (pts[1][1], f->planepts[1]);
- VectorCopy (pts[2][1], f->planepts[2]);
-
- f = Face_Alloc();
- f->texdef = *texdef;
- f->next = b->brush_faces;
- b->brush_faces = f;
-
- VectorCopy (pts[2][0], f->planepts[0]);
- VectorCopy (pts[1][0], f->planepts[1]);
- VectorCopy (pts[0][0], f->planepts[2]);
-
- return b;
- }
-
-
- /*
- =============
- Brush_MakeSided
-
- Makes the current brushhave the given number of 2d sides
- =============
- */
- void Brush_MakeSided (int sides)
- {
- int i;
- vec3_t mins, maxs;
- brush_t *b;
- texdef_t *texdef;
- face_t *f;
- vec3_t mid;
- float width;
- float sv, cv;
-
- if (sides < 3)
- {
- Sys_Status ("Bad sides number", 0);
- return;
- }
-
- if (!QE_SingleBrush ())
- {
- Sys_Status ("Must have a single brush selected", 0 );
- return;
- }
-
- b = selected_brushes.next;
- VectorCopy (b->mins, mins);
- VectorCopy (b->maxs, maxs);
- texdef = &g_qeglobals.d_texturewin.texdef;
-
- Brush_Free (b);
-
- // find center of brush
- width = 8;
- for (i=0 ; i<2 ; i++)
- {
- mid[i] = (maxs[i] + mins[i])*0.5;
- if (maxs[i] - mins[i] > width)
- width = maxs[i] - mins[i];
- }
- width /= 2;
-
- b = qmalloc (sizeof(brush_t));
-
- // create top face
- f = Face_Alloc();
- f->texdef = *texdef;
- f->next = b->brush_faces;
- b->brush_faces = f;
-
- f->planepts[2][0] = mins[0];f->planepts[2][1] = mins[1];f->planepts[2][2] = maxs[2];
- f->planepts[1][0] = maxs[0];f->planepts[1][1] = mins[1];f->planepts[1][2] = maxs[2];
- f->planepts[0][0] = maxs[0];f->planepts[0][1] = maxs[1];f->planepts[0][2] = maxs[2];
-
- // create bottom face
- f = Face_Alloc();
- f->texdef = *texdef;
- f->next = b->brush_faces;
- b->brush_faces = f;
-
- f->planepts[0][0] = mins[0];f->planepts[0][1] = mins[1];f->planepts[0][2] = mins[2];
- f->planepts[1][0] = maxs[0];f->planepts[1][1] = mins[1];f->planepts[1][2] = mins[2];
- f->planepts[2][0] = maxs[0];f->planepts[2][1] = maxs[1];f->planepts[2][2] = mins[2];
-
- for (i=0 ; i<sides ; i++)
- {
- f = Face_Alloc();
- f->texdef = *texdef;
- f->next = b->brush_faces;
- b->brush_faces = f;
-
- sv = sin (i*3.14159265*2/sides);
- cv = cos (i*3.14159265*2/sides);
-
- f->planepts[0][0] = floor(mid[0]+width*cv+0.5);
- f->planepts[0][1] = floor(mid[1]+width*sv+0.5);
- f->planepts[0][2] = mins[2];
-
- f->planepts[1][0] = f->planepts[0][0];
- f->planepts[1][1] = f->planepts[0][1];
- f->planepts[1][2] = maxs[2];
-
- f->planepts[2][0] = floor(f->planepts[0][0] - width*sv + 0.5);
- f->planepts[2][1] = floor(f->planepts[0][1] + width*cv + 0.5);
- f->planepts[2][2] = maxs[2];
-
- }
-
- Brush_AddToList (b, &selected_brushes);
-
- Entity_LinkBrush (world_entity, b);
-
- Brush_Build( b );
-
- Sys_UpdateWindows (W_ALL);
- }
-
-
- /*
- =============
- Brush_Free
-
- Frees the brush with all of its faces and display list.
- Unlinks the brush from whichever chain it is in.
- Decrements the owner entity's brushcount.
- Removes owner entity if this was the last brush
- unless owner is the world.
- =============
- */
- void Brush_Free (brush_t *b)
- {
- face_t *f, *next;
-
- // free faces
- for (f=b->brush_faces ; f ; f=next)
- {
- next = f->next;
- Face_Free( f );
- }
-
- /*
- for ( i = 0; i < b->d_numwindings; i++ )
- {
- if ( b->d_windings[i] )
- {
- FreeWinding( b->d_windings[i] );
- b->d_windings[i] = 0;
- }
- }
- */
-
- // unlink from active/selected list
- if (b->next)
- Brush_RemoveFromList (b);
-
- // unlink from entity list
- if (b->onext)
- Entity_UnlinkBrush (b);
-
- free (b);
- }
-
- /*
- ============
- Brush_Move
- ============
- */
- void Brush_Move (brush_t *b, vec3_t move)
- {
- int i;
- face_t *f;
-
- for (f=b->brush_faces ; f ; f=f->next)
- for (i=0 ; i<3 ; i++)
- VectorAdd (f->planepts[i], move, f->planepts[i]);
- Brush_Build( b );
- }
-
- /*
- ============
- Brush_Clone
-
- Does NOT add the new brush to any lists
- ============
- */
- brush_t *Brush_Clone (brush_t *b)
- {
- brush_t *n;
- face_t *f, *nf;
-
- n = qmalloc(sizeof(brush_t));
- n->owner = b->owner;
- for (f=b->brush_faces ; f ; f=f->next)
- {
- nf = Face_Clone( f );
- nf->next = n->brush_faces;
- n->brush_faces = nf;
- }
- return n;
- }
-
- /*
- ==============
- Brush_Ray
-
- Itersects a ray with a brush
- Returns the face hit and the distance along the ray the intersection occured at
- Returns NULL and 0 if not hit at all
- ==============
- */
- face_t *Brush_Ray (vec3_t origin, vec3_t dir, brush_t *b, float *dist)
- {
- face_t *f, *firstface;
- vec3_t p1, p2;
- float frac, d1, d2;
- int i;
-
- VectorCopy (origin, p1);
- for (i=0 ; i<3 ; i++)
- p2[i] = p1[i] + dir[i]*16384;
-
- for (f=b->brush_faces ; f ; f=f->next)
- {
- d1 = DotProduct (p1, f->plane.normal) - f->plane.dist;
- d2 = DotProduct (p2, f->plane.normal) - f->plane.dist;
- if (d1 >= 0 && d2 >= 0)
- {
- *dist = 0;
- return NULL; // ray is on front side of face
- }
- if (d1 <=0 && d2 <= 0)
- continue;
- // clip the ray to the plane
- frac = d1 / (d1 - d2);
- if (d1 > 0)
- {
- firstface = f;
- for (i=0 ; i<3 ; i++)
- p1[i] = p1[i] + frac *(p2[i] - p1[i]);
- }
- else
- {
- for (i=0 ; i<3 ; i++)
- p2[i] = p1[i] + frac *(p2[i] - p1[i]);
- }
- }
-
- // find distance p1 is along dir
- VectorSubtract (p1, origin, p1);
- d1 = DotProduct (p1, dir);
-
- *dist = d1;
-
- return firstface;
- }
-
- void Brush_AddToList (brush_t *b, brush_t *list)
- {
- if (b->next || b->prev)
- Error ("Brush_RemoveFromList: allready linked");
- b->next = list->next;
- list->next->prev = b;
- list->next = b;
- b->prev = list;
- }
-
- void Brush_RemoveFromList (brush_t *b)
- {
- if (!b->next || !b->prev)
- Error ("Brush_RemoveFromList: not linked");
- b->next->prev = b->prev;
- b->prev->next = b->next;
- b->next = b->prev = NULL;
- }
-
- void Brush_SetTexture (brush_t *b, texdef_t *texdef)
- {
- face_t *f;
-
- for (f=b->brush_faces ; f ; f=f->next)
- f->texdef = *texdef;
- Brush_Build( b );
- }
-
-
- qboolean ClipLineToFace (vec3_t p1, vec3_t p2, face_t *f)
- {
- float d1, d2, fr;
- int i;
- float *v;
-
- d1 = DotProduct (p1, f->plane.normal) - f->plane.dist;
- d2 = DotProduct (p2, f->plane.normal) - f->plane.dist;
-
- if (d1 >= 0 && d2 >= 0)
- return false; // totally outside
- if (d1 <= 0 && d2 <= 0)
- return true; // totally inside
-
- fr = d1 / (d1 - d2);
-
- if (d1 > 0)
- v = p1;
- else
- v = p2;
-
- for (i=0 ; i<3 ; i++)
- v[i] = p1[i] + fr*(p2[i] - p1[i]);
-
- return true;
- }
-
-
- int AddPlanept (float *f)
- {
- int i;
-
- for (i=0 ; i<g_qeglobals.d_num_move_points ; i++)
- if (g_qeglobals.d_move_points[i] == f)
- return 0;
- g_qeglobals.d_move_points[g_qeglobals.d_num_move_points++] = f;
- return 1;
- }
-
- /*
- ==============
- Brush_SelectFaceForDragging
-
- Adds the faces planepts to move_points, and
- rotates and adds the planepts of adjacent face if shear is set
- ==============
- */
- void Brush_SelectFaceForDragging (brush_t *b, face_t *f, qboolean shear)
- {
- int i;
- face_t *f2;
- winding_t *w;
- float d;
- brush_t *b2;
- int c;
-
- if (b->owner->eclass->fixedsize)
- return;
-
- c = 0;
- for (i=0 ; i<3 ; i++)
- c += AddPlanept (f->planepts[i]);
- if (c == 0)
- return; // allready completely added
-
- // select all points on this plane in all brushes the selection
- for (b2=selected_brushes.next ; b2 != &selected_brushes ; b2 = b2->next)
- {
- if (b2 == b)
- continue;
- for (f2=b2->brush_faces ; f2 ; f2=f2->next)
- {
- for (i=0 ; i<3 ; i++)
- if (fabs(DotProduct(f2->planepts[i], f->plane.normal)
- -f->plane.dist) > ON_EPSILON)
- break;
- if (i==3)
- { // move this face as well
- Brush_SelectFaceForDragging (b2, f2, shear);
- break;
- }
- }
- }
-
-
- // if shearing, take all the planes adjacent to
- // selected faces and rotate their points so the
- // edge clipped by a selcted face has two of the points
- if (!shear)
- return;
-
- for (f2=b->brush_faces ; f2 ; f2=f2->next)
- {
- if (f2 == f)
- continue;
- w = MakeFaceWinding (b, f2);
- if (!w)
- continue;
-
- // any points on f will become new control points
- for (i=0 ; i<w->numpoints ; i++)
- {
- d = DotProduct (w->points[i], f->plane.normal)
- - f->plane.dist;
- if (d > -ON_EPSILON && d < ON_EPSILON)
- break;
- }
-
- //
- // if none of the points were on the plane,
- // leave it alone
- //
- if (i != w->numpoints)
- {
- if (i == 0)
- { // see if the first clockwise point was the
- // last point on the winding
- d = DotProduct (w->points[w->numpoints-1]
- , f->plane.normal) - f->plane.dist;
- if (d > -ON_EPSILON && d < ON_EPSILON)
- i = w->numpoints - 1;
- }
-
- AddPlanept (f2->planepts[0]);
-
- VectorCopy (w->points[i], f2->planepts[0]);
- if (++i == w->numpoints)
- i = 0;
-
- // see if the next point is also on the plane
- d = DotProduct (w->points[i]
- , f->plane.normal) - f->plane.dist;
- if (d > -ON_EPSILON && d < ON_EPSILON)
- AddPlanept (f2->planepts[1]);
-
- VectorCopy (w->points[i], f2->planepts[1]);
- if (++i == w->numpoints)
- i = 0;
-
- // the third point is never on the plane
-
- VectorCopy (w->points[i], f2->planepts[2]);
- }
-
- free(w);
- }
- }
-
- /*
- ==============
- Brush_SideSelect
-
- The mouse click did not hit the brush, so grab one or more side
- planes for dragging
- ==============
- */
- void Brush_SideSelect (brush_t *b, vec3_t origin, vec3_t dir
- , qboolean shear)
- {
- face_t *f, *f2;
- vec3_t p1, p2;
-
- for (f=b->brush_faces ; f ; f=f->next)
- {
- VectorCopy (origin, p1);
- VectorMA (origin, 16384, dir, p2);
-
- for (f2=b->brush_faces ; f2 ; f2=f2->next)
- {
- if (f2 == f)
- continue;
- ClipLineToFace (p1, p2, f2);
- }
-
- if (f2)
- continue;
-
- if (VectorCompare (p1, origin))
- continue;
- if (ClipLineToFace (p1, p2, f))
- continue;
-
- Brush_SelectFaceForDragging (b, f, shear);
- }
-
-
- }
-
- void Brush_BuildWindings( brush_t *b )
- {
- winding_t *w;
- face_t *face;
- vec_t v;
-
- Brush_SnapPlanepts( b );
-
- // clear the mins/maxs bounds
- b->mins[0] = b->mins[1] = b->mins[2] = 99999;
- b->maxs[0] = b->maxs[1] = b->maxs[2] = -99999;
-
- Brush_MakeFacePlanes (b);
-
- face = b->brush_faces;
-
- for ( ; face ; face=face->next)
- {
- int i, j;
-
- w = face->face_winding = MakeFaceWinding (b, face);
- face->d_texture = Texture_ForName( face->texdef.name );
-
- if (!w)
- {
- continue;
- }
-
- for (i=0 ; i<w->numpoints ; i++)
- {
- // add to bounding box
- for (j=0 ; j<3 ; j++)
- {
- v = w->points[i][j];
- if (v > b->maxs[j])
- b->maxs[j] = v;
- if (v < b->mins[j])
- b->mins[j] = v;
- }
- }
- // setup s and t vectors, and set color
- BeginTexturingFace( b, face, face->d_texture);
-
-
- for (i=0 ; i<w->numpoints ; i++)
- {
- EmitTextureCoordinates( w->points[i], face->d_texture, face);
- }
- }
- }
-
- /*
- ==================
- Brush_RemoveEmptyFaces
-
- Frees any overconstraining faces
- ==================
- */
- void Brush_RemoveEmptyFaces ( brush_t *b )
- {
- face_t *f, *next;
-
- f = b->brush_faces;
- b->brush_faces = NULL;
-
- for ( ; f ; f=next)
- {
- next = f->next;
- if (!f->face_winding)
- Face_Free (f);
- else
- {
- f->next = b->brush_faces;
- b->brush_faces = f;
- }
-
- }
- }
-
- void Brush_Draw( brush_t *b )
- {
- face_t *face;
- int i, order;
- qtexture_t *prev = 0;
- winding_t *w;
-
- if (b->owner->eclass->fixedsize && camera.draw_mode == cd_texture)
- glDisable (GL_TEXTURE_2D);
-
- // guarantee the texture will be set first
- prev = NULL;
- for (face = b->brush_faces,order = 0 ; face ; face=face->next, order++)
- {
- w = face->face_winding;
- if (!w)
- continue; // freed face
-
- if ( face->d_texture != prev && camera.draw_mode == cd_texture)
- {
- // set the texture for this face
- prev = face->d_texture;
- glBindTexture( GL_TEXTURE_2D, face->d_texture->texture_number );
- }
-
- glColor3fv( face->d_color );
-
- // draw the polygon
- glBegin(GL_POLYGON);
- for (i=0 ; i<w->numpoints ; i++)
- {
- if (camera.draw_mode == cd_texture)
- glTexCoord2fv( &w->points[i][3] );
- glVertex3fv(w->points[i]);
- }
- glEnd();
- }
-
- if (b->owner->eclass->fixedsize && camera.draw_mode == cd_texture)
- glEnable (GL_TEXTURE_2D);
-
- glBindTexture( GL_TEXTURE_2D, 0 );
- }
-
- void Face_Draw( face_t *f )
- {
- int i;
-
- if ( f->face_winding == 0 )
- return;
- glBegin( GL_POLYGON );
- for ( i = 0 ; i < f->face_winding->numpoints; i++)
- glVertex3fv( f->face_winding->points[i] );
- glEnd();
- }
-
- void Brush_DrawXY( brush_t *b )
- {
- face_t *face;
- int order;
- winding_t *w;
- int i;
-
- for (face = b->brush_faces,order = 0 ; face ; face=face->next, order++)
- {
- // only draw up facing polygons
- if (face->plane.normal[2] <= 0)
- continue;
-
- w = face->face_winding;
- if (!w)
- continue;
-
- // draw the polygon
- glBegin(GL_LINE_LOOP);
- for (i=0 ; i<w->numpoints ; i++)
- glVertex3fv(w->points[i]);
- glEnd();
- }
-
- // optionally add a text label
- if ( g_qeglobals.d_savedinfo.show_names )
- DrawBrushEntityName (b);
- }
-
- face_t *Face_Alloc( void )
- {
- face_t *f = qmalloc( sizeof( *f ) );
-
- return f;
- }
-
- void Face_Free( face_t *f )
- {
- assert( f != 0 );
-
- if ( f->face_winding )
- free( f->face_winding ), f->face_winding = 0;
- free( f );
- }
-